package com.example.private_auto_install.toolby;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public abstract class RSAEnCoder {
    public static final String KEY_ALGORITHM = "RSA";
    public static final String KEY_PROVIDER = "BC";
    public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";

    public RSAEnCoder() {
    }

    public static Map<String, Object> initKeys(String seed) throws Exception {
        Map<String, Object> keyMap = new HashMap();
        Security.addProvider(new BouncyCastleProvider());
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
        keyPairGenerator.initialize(1024, new SecureRandom(seed.getBytes()));
        KeyPair pair = keyPairGenerator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey)pair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)pair.getPrivate();
        KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
        RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(rsaPublicKey.getModulus().toString()), new BigInteger(rsaPublicKey.getPublicExponent().toString()));
        RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(new BigInteger(rsaPrivateKey.getModulus().toString()), new BigInteger(rsaPrivateKey.getPrivateExponent().toString()));
        PublicKey publicKey = factory.generatePublic(pubKeySpec);
        PrivateKey privateKey = factory.generatePrivate(priKeySpec);
        System.out.println("公钥：" + pubKeySpec.getModulus() + "----" + pubKeySpec.getPublicExponent());
        System.out.println("私钥：" + priKeySpec.getModulus() + "----" + priKeySpec.getPrivateExponent());
        keyMap.put("publicKey", publicKey);
        keyMap.put("privateKey", privateKey);
        return keyMap;
    }

    public static byte[] encryptRSA(byte[] data, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA", "BC");
        cipher.init(1, privateKey);
        int dataSize = cipher.getOutputSize(data.length);
        int blockSize = cipher.getBlockSize();
        int blockNum;
        if (data.length % blockSize == 0) {
            blockNum = data.length / blockSize;
        } else {
            blockNum = data.length / blockSize + 1;
        }

        byte[] raw = new byte[dataSize * blockNum];

        for(int i = 0; data.length - i * blockSize > 0; ++i) {
            if (data.length - i * blockSize > blockSize) {
                cipher.doFinal(data, i * blockSize, blockSize, raw, i * dataSize);
            } else {
                cipher.doFinal(data, i * blockSize, data.length - i * blockSize, raw, i * dataSize);
            }
        }

        return raw;
    }

    public static String sign(byte[] encoderData, PrivateKey privateKey) throws Exception {
        Signature sig = Signature.getInstance("SHA1WithRSA", "BC");
        sig.initSign(privateKey);
        sig.update(encoderData);
        return new String(Base64.encodeBase64(sig.sign()));
    }

    public static boolean verify(byte[] encoderData, String sign, PublicKey publicKey) throws Exception {
        Signature sig = Signature.getInstance("SHA1WithRSA", "BC");
        sig.initVerify(publicKey);
        sig.update(encoderData);
        return sig.verify(Base64.decodeBase64(sign.getBytes()));
    }

    public static PrivateKey getPrivateKey(String modulus, String exponent) throws Exception {
        BigInteger b1 = new BigInteger(modulus);
        BigInteger b2 = new BigInteger(exponent);
        Security.addProvider(new BouncyCastleProvider());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
        RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);
        return (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
    }
}